#include "codegenerator.h"

/*##############################################################################
#                                                                              #
# MAIN                                                                         #
#                                                                              #
##############################################################################*/
int main(int argc, char **argv)
{
    if ( argc < 2 ) {
        printf("\nPRIMEVAL: usage \"codegenerator <file>\"\n");
        return 1;
    }
    openFile(argv[1]);

    writeInstruction(JSR, 0, 0, 15*4);

    writeInstruction(ADDI, 1, 0, 1);
    writeInstruction(ADDI, 2, 0, 1);
    writeInstruction(ADDI, 3, 0, 0);
    writeInstruction(ADDI, 4, 0, 3);
    writeInstruction(POP, 5, STACKPOINTER, 0);
    writeInstruction(CMP, 6, 4, 5);
    writeInstruction(BGT, 6, 0, 6);
        writeInstruction(ADD, 3, 1, 2);
        writeInstruction(ADD, 1, 0, 2);
        writeInstruction(ADD, 2, 0, 3);
        writeInstruction(ADDI, 4, 4, 1);
    writeInstruction(BR, 0, 0, -6);
    writeInstruction(PSH, 2, STACKPOINTER, 0);
    writeInstruction(RET, 0, 0, LINKREGISTER);

    writeInstruction(READI, 1, 0, 0);
    writeInstruction(PSH, 1, STACKPOINTER, 0);
    writeInstruction(BSR, 0, 0, -16);
    writeInstruction(POP, 1, STACKPOINTER, 0);
    writeInstruction(PRINTI, 1, 0, 0);
    writeInstruction(TRAP, 0, 0, 0);

    closeFile();
    return 0;
}

/*##############################################################################
#                                                                              #
# ENCODE                                                                       #
#                                                                              #
##############################################################################*/
void encode(unsigned long *result, int op, char a, char b, int c) {
    *result = op & 0x3F;
    if ( op >= 1 && op <= 33 ) {        // if Format 0 or Format 1
        *result <<= 5;
        *result |= a & 0x1F;
        *result <<= 5;
        *result |= b & 0x1F;

        if ( op >= 1 && op <= 22 ) {   // if Format 0
            if ( c < 0 ) {
                *result <<= 16;
                *result |= ( 65536 + c ) & 0xFFFF;
            } else {
                *result <<= 16;
                *result |= c & 0xFFFF;
            }
        }
        else {  // if Format 1
            *result <<= 16;
            *result |= c & 0x1F;
    }   }
    else {      // if Format 2
        *result <<= 26;
        *result |= c & 0x3FFFFFF;
    }
}

/*##############################################################################
#                                                                              #
# FILE I/O                                                                     #
#                                                                              #
##############################################################################*/
void openFile(char* fileName) {
    filePointer = fopen(fileName, "w");
}

void closeFile() {
    fclose(filePointer);
}

void writeInstruction(int op, char a, char b, int c) {
    unsigned long instruction;
    encode(&instruction, op, a, b, c);
    fwrite(&instruction, sizeof(instruction), 1, filePointer);
}
